default.
+BUILDING for ACM Security Testing
+=================================
+
+A number of tests have been added to test the access control module (ACM)
+in the Xen hypervisor and the tools for supporting ACM. Those tests are
+located in the security-acm directory. If ACM support is compiled into Xen
+(see the user guide for how to do this) those tests can be run with the
+following command from the xm-test directory
+
+./runtest.sh [...] -g security <report>
+
+Some of these tests will work even without support of ACM by Xen.
+
+Several of these tests require the privilege of being allowed to label
+resources and will otherwise be skipped. By default the test suite
+is not allowed to automatically label resources since this may affect
+existing labels. To enable this, the test suite must be configured with
+the following parameter passed to the configure scripts (in addition to
+any other desired parameters)
+
+./configure --enable-full-labeling
+
+To revoke the privilege at a later time run the configure scripts without
+this parameter:
+
+./configure
+
+If a 'make' has previously been run for building the test suite, it is not
+necessary to run 'make' again just for enabling or disabling the automatic
+labeling of resources.
+
+
Running
=======
AM_CONDITIONAL(HVM, test x$ENABLE_HVM = xTrue)
AC_SUBST(ENABLE_HVM)
+AC_ARG_ENABLE(full-labeling,
+ [[ --enable-full-labeling allows the test suite to label all resources]],
+ [
+ ENABLE_LABELING=True
+ ],[
+ ENABLE_LABELING=False
+ ])
+
+if test "x$ENABLE_LABELING" = "xTrue"; then
+ echo "ACM_LABEL_RESOURCES = True" > lib/XmTestLib/acm_config.py
+else
+ rm -f lib/XmTestLib/acm_config.py*
+fi
+
# Network needs to know ips to use: dhcp or a range of IPs in the form
# of: 192.168.1.1-192.168.1.100
# If not dhcp, a netmask and network address must be supplied. Defaults to
tests/restore/Makefile
tests/save/Makefile
tests/sched-credit/Makefile
+ tests/security-acm/Makefile
tests/sedf/Makefile
tests/shutdown/Makefile
tests/sysrq/Makefile
restore
save
sched-credit
+security-acm
shutdown
sysrq
unpause
--- /dev/null
+security-acm
self.defaultOpts["disk"] = []
self.defaultOpts["vif"] = []
self.defaultOpts["vtpm"] = []
+ if isACMEnabled():
+ self.defaultOpts["access_control"] = []
self.opts = self.defaultOpts
--- /dev/null
+#!/usr/bin/python
+"""
+ Copyright (C) International Business Machines Corp., 2006
+ Author: Stefan Berger <stefanb@us.ibm.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; under version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+from Test import *
+from xen.util import security
+
+try:
+ from acm_config import *
+except:
+ ACM_LABEL_RESOURCES = False
+
+labeled_resources = {}
+acm_verbose = False
+
+def isACMEnabled():
+ return security.on()
+
+
+def ACMLoadPolicy(policy='xm-test'):
+ s, o = traceCommand("xm makepolicy %s" % (policy))
+ if s != 0:
+ FAIL("Need to be able to do 'xm makepolicy %s' but could not" %
+ (policy))
+ s, o = traceCommand("xm loadpolicy %s" % (policy))
+ if s != 0:
+ FAIL("Could not load the required policy '%s'.\n"
+ "Start the system without any policy.\n%s" %
+ (policy, o))
+
+
+# Applications may label resources explicitly by calling this function
+def ACMLabelResource(resource, label='red'):
+ if acm_verbose:
+ print "labeling resource %s with label %s" % (resource, label)
+ if not ACM_LABEL_RESOURCES:
+ SKIP("Skipping test since not allowed to label resources in "
+ "test suite")
+ if not isACMResourceLabeled(resource):
+ ACMUnlabelResource(resource)
+ s, o = traceCommand("xm addlabel %s res %s" % (label, resource))
+ if s != 0:
+ FAIL("Could not add label to resource")
+ else:
+ labeled_resources["%s" % resource] = 1
+
+
+# Application may remove a label from a resource. It has to call this
+# function and must do so once a resource for re-labeling a resource
+def ACMUnlabelResource(resource):
+ s, o = traceCommand("xm rmlabel res %s" % (resource))
+ labeled_resources["%s" % resource] = 0
+
+
+def isACMResourceLabeled(resource):
+ """ Check whether a resource has been labeled using this API
+ and while running the application """
+ try:
+ if labeled_resources["%s" % resource] == 1:
+ if acm_verbose:
+ print "resource %s already labeled!" % resource
+ return True
+ except:
+ return False
+ return False
pause \
reboot \
sched-credit \
+ security-acm \
sedf \
shutdown \
sysrq \
--- /dev/null
+#!/usr/bin/python
+
+# Copyright (C) International Business Machines Corp., 2006
+# Author: Stefan Berger <stefanb@us.ibm.com>
+#
+# A couple of simple tests that test ACM security extensions
+# for the xm tool. The following xm subcommands are tested:
+#
+# - makepolicy
+# - labels
+# - rmlabel
+# - addlabel
+# - getlabel
+# - resources
+
+from XmTestLib import *
+from xen.util import security
+import commands
+import os
+import re
+
+testpolicy = "xm-test"
+testlabel = "blue"
+vmconfigfile = "/tmp/xm-test.conf"
+testresource = "phy:ram0"
+
+status, output = traceCommand("xm makepolicy %s" % (testpolicy))
+if status != 0 or output != "":
+ FAIL("'xm makepolicy' failed with status %d and output\n%s" %
+ (status,output));
+
+status, output = traceCommand("xm labels %s" % (testpolicy))
+if status != 0:
+ FAIL("'xm labels' failed with status %d.\n" % status)
+
+#Need to get a vm config file - just have it written to a file
+domain = XmTestDomain()
+domain.config.write(vmconfigfile)
+
+#Whatever label it might have - remove it
+status, output = traceCommand("xm rmlabel dom %s" %
+ (vmconfigfile))
+
+status, output = traceCommand("xm addlabel %s dom %s %s" %
+ (testlabel, vmconfigfile, testpolicy))
+if status != 0:
+ FAIL("'xm addlabel' failed with status %d.\n" % status)
+
+status, output = traceCommand("xm getlabel dom %s" %
+ (vmconfigfile))
+
+if status != 0:
+ FAIL("'xm getlabel' failed with status %d, output:\n%s" %
+ (status, output))
+if output != "policy=%s,label=%s" % (testpolicy,testlabel):
+ FAIL("Received unexpected output from 'xm getlabel': \n%s" %
+ (output))
+
+
+status, output = traceCommand("xm rmlabel dom %s" %
+ (vmconfigfile))
+
+if status != 0:
+ FAIL("'xm rmlabel' failed with status %d, output: \n%s" %
+ (status,output))
+if output != "":
+ FAIL("Received unexpected output from 'xm rmlabel': \n%s" %
+ (output))
+
+status, output = traceCommand("xm getlabel dom %s" %
+ (vmconfigfile))
+
+if output != "Error: 'Domain not labeled'":
+ FAIL("Received unexpected output from 'xm getlabel': \n%s" %
+ (output))
+
+#Whatever label the resource might have, remove it
+status, output = traceCommand("xm rmlabel res %s" %
+ (testresource))
+
+status, output = traceCommand("xm addlabel %s res %s %s" %
+ (testlabel, testresource, testpolicy))
+if status != 0:
+ FAIL("'xm addlabel' on resource failed with status %d.\n" % status)
+
+status, output = traceCommand("xm getlabel res %s" % (testresource))
+
+if status != 0:
+ FAIL("'xm getlabel' on resource failed with status %d, output:\n%s" %
+ (status, output))
+if output != "policy=%s,label=%s" % (testpolicy,testlabel):
+ FAIL("Received unexpected output from 'xm getlabel': \n%s" %
+ (output))
+
+status, output = traceCommand("xm resources")
+
+if status != 0:
+ FAIL("'xm resources' did not run properly")
+if not re.search(security.unify_resname(testresource), output):
+ FAIL("'xm resources' did not show the tested resource '%s'." %
+ testresource)
+
+status, output = traceCommand("xm rmlabel res %s" %
+ (testresource))
+
+if status != 0:
+ FAIL("'xm rmlabel' on resource failed with status %d, output: \n%s" %
+ (status,output))
+if output != "":
+ FAIL("Received unexpected output from 'xm rmlabel': \n%s" %
+ (output))
+
+status, output = traceCommand("xm getlabel res %s" %
+ (testresource))
+
+if output != "Error: 'Resource not labeled'":
+ FAIL("Received unexpected output from 'xm getlabel': \n%s" %
+ (output))
--- /dev/null
+#!/usr/bin/python
+
+# Copyright (C) International Business Machines Corp., 2006
+# Author: Stefan Berger <stefanb@us.ibm.com>
+#
+# Simple test that starts two labeled domains; both domains should start
+#
+# The following xm subcommands are tested:
+# - dumppolicy
+# - labels
+
+from XmTestLib import *
+from acm_utils import *
+import commands
+import os
+
+testlabel1 = "green"
+testlabel2 = "red"
+
+status, output = traceCommand("xm labels")
+
+labels = ["SystemManagement", "blue", "red", "green"]
+for l in labels:
+ if not re.search(l, output):
+ FAIL("Label '%s' not found in current policy!", l)
+
+status, output = traceCommand("xm dumppolicy")
+if status != 0:
+ FAIL("'xm dumppolicy' returned an error code.")
+lines = ["ssidref 0: 00 00 00 00",
+ "ssidref 1: 01 00 00 00",
+ "ssidref 2: 00 01 00 00",
+ "ssidref 3: 00 00 01 00",
+ "ssidref 4: 00 00 00 01"]
+for l in lines:
+ if not re.search(l, output):
+ FAIL("Could not find '%s' in output of 'xm dumppolicy'" % l)
+
+config = {"access_control":"policy=%s,label=%s" % (testpolicy,testlabel1)}
+verbose = True
+domain1 = XmTestDomain(name="domain-%s" % testlabel1,
+ extraConfig=config)
+
+try:
+ domain1.start(noConsole=True)
+except DomainError, e:
+ if verbose:
+ print e.extra
+ FAIL("Unable to start 1st labeled test domain.")
+
+config = {"access_control":"policy=%s,label=%s" % (testpolicy,testlabel2)}
+
+domain2 = XmTestDomain(name="domain-%s" % testlabel2,
+ extraConfig=config)
+
+try:
+ domain2.start(noConsole=True)
+except DomainError, e:
+ if verbose:
+ print e.extra
+ FAIL("Unable to start 2nd labeled test domain.")
+
+domain2.destroy()
+domain1.destroy()
--- /dev/null
+#!/usr/bin/python
+
+# Copyright (C) International Business Machines Corp., 2006
+# Author: Stefan Berger <stefanb@us.ibm.com>
+#
+# A test that exercises the conflict set of the chinese wall policy.
+# Start a first domain and then a second one. The second one is
+# expected NOT to be starteable.
+
+from XmTestLib import *
+from acm_utils import *
+import commands
+import os
+
+testlabel1 = "blue"
+testlabel2 = "red"
+
+config = {"access_control":"policy=%s,label=%s" % (testpolicy,testlabel1)}
+
+domain1 = XmTestDomain(name="domain-%s" % testlabel1,
+ extraConfig=config)
+
+try:
+ domain1.start(noConsole=True)
+except DomainError, e:
+ if verbose:
+ print e.extra
+ FAIL("Unable to start 1st labeled test domain")
+
+# Verify with xm dry-run
+status, output = traceCommand("xm dry-run /tmp/xm-test.conf | "
+ "grep -v \"Dry Run\"")
+if status != 0:
+ FAIL("'xm dry-run' failed")
+if not re.search("PERMITTED", output):
+ FAIL("'xm dry-run' did not succeed.")
+
+config = {"access_control":"policy=%s,label=%s" % (testpolicy,testlabel2)}
+
+domain2 = XmTestDomain(name="domain-%s" % testlabel2,
+ extraConfig=config)
+
+try:
+ domain2.start(noConsole=True)
+ # Should never get here!
+ FAIL("Could start a domain in a conflict set - "
+ "this should not be possible")
+except DomainError, e:
+ #This is exactly what we want in this case
+ status = 0
+
+# Verify with xm dry-run
+status, output = traceCommand("xm dry-run /tmp/xm-test.conf | "
+ "grep -v \"Dry Run\"")
+if status != 0:
+ FAIL("'xm dry-run' failed.")
+if not re.search("PERMITTED", output):
+ FAIL("'xm dry-run' did not show that operation was permitted.")
+
+domain1.destroy()
--- /dev/null
+#!/usr/bin/python
+
+# Copyright (C) International Business Machines Corp., 2006
+# Author: Stefan Berger <stefanb@us.ibm.com>
+#
+# Simple test that starts two labeled domains using labeled resources each
+#
+
+from XmTestLib import *
+from acm_utils import *
+import commands
+import os
+
+testlabel1 = "green"
+resource1 = "phy:ram0"
+testlabel2 = "red"
+resource2 = "phy:/dev/ram1"
+
+config = {"access_control":"policy=%s,label=%s" % (testpolicy,testlabel1),
+ "disk" :"%s,hda1,w" % (resource1)}
+domain1 = XmTestDomain(name="domain-%s" % testlabel1,
+ extraConfig=config)
+
+# Explicity label the resource
+ACMLabelResource(resource1, testlabel1)
+
+try:
+ domain1.start(noConsole=True)
+except DomainError, e:
+ if verbose:
+ print e.extra
+ FAIL("Unable to start 1st labeled test domain.")
+
+# Verify with xm dry-run
+status, output = traceCommand("xm dry-run /tmp/xm-test.conf | "
+ "grep -v \"Dry Run\"")
+
+if status != 0:
+ FAIL("'xm dry-run' failed")
+if not re.search("%s: PERMITTED" % resource1, output):
+ FAIL("'xm dry-run' did not succeed.")
+
+config = {"access_control":"policy=%s,label=%s" % (testpolicy,testlabel2),
+ "disk" :"%s,hda1,w" % (resource2)}
+
+domain2 = XmTestDomain(name="domain-%s" % testlabel2,
+ extraConfig=config)
+
+# Explicity label the resource
+ACMLabelResource(resource2, testlabel2)
+
+try:
+ domain2.start(noConsole=True)
+except DomainError, e:
+ if verbose:
+ print e.extra
+ FAIL("Unable to start 2nd labeled test domain.")
+
+# Verify with xm dry-run
+status, output = traceCommand("xm dry-run /tmp/xm-test.conf | "
+ "grep -v \"Dry Run\"")
+
+if status != 0:
+ FAIL("'xm dry-run' failed")
+if not re.search("%s: PERMITTED" % resource2, output):
+ FAIL("'xm dry-run' did not succeed.")
+
+domain2.destroy()
+domain1.destroy()
--- /dev/null
+#!/usr/bin/python
+
+# Copyright (C) International Business Machines Corp., 2006
+# Author: Stefan Berger <stefanb@us.ibm.com>
+#
+# A test that tries to start a domain using a resource that it is
+# not supposed to be able to use due to its labeling
+
+from XmTestLib import *
+from acm_utils import *
+import commands
+import os
+
+testlabel1 = "blue"
+resource1 = "phy:ram0"
+
+config = {"access_control":"policy=%s,label=%s" % (testpolicy,testlabel1),
+ "disk" :"%s,hda1,w" % (resource1)}
+
+domain1 = XmTestDomain(name="domain-%s" % testlabel1,
+ extraConfig=config)
+
+ACMLabelResource(resource1,"red")
+
+try:
+ domain1.start(noConsole=True)
+ # Should never get here
+ FAIL("Could start domain with resource that it is not supposed to access.")
+except DomainError, e:
+ #That's exactly what we want to have in this case
+ dummy = 0
+
+# Verify via dry-run
+status, output = traceCommand("xm dry-run /tmp/xm-test.conf | "
+ "grep -v \"Dry Run\"")
+if not re.search("%s: DENIED" %resource1, output):
+ FAIL("'xm dry-run' did not show expected result that operation was NOT "
+ "permitted: \n%s" % output)
--- /dev/null
+#!/usr/bin/python
+
+# Copyright (C) International Business Machines Corp., 2005
+# Author: Stefan Berger <stefanb@us.ibm.com>
+# Based on block-create/01_block_attach_device_pos.py
+#
+# Create a domain and attach 2 resources to it. The first resource
+# should be attacheable, the 2nd one should not be due to the label it has.
+
+import re
+from XmTestLib import *
+from XmTestLib import block_utils
+from acm_utils import *
+
+testlabel1 = "blue"
+resource1 = "phy:ram1"
+resourcelabel1 = "blue"
+resource2 = "phy:/dev/ram0"
+resourcelabel2 = "red"
+
+if ENABLE_HVM_SUPPORT:
+ SKIP("Block-attach not supported for HVM domains")
+
+# Create a domain (default XmTestDomain, with our ramdisk)
+config = {"access_control":"policy=%s,label=%s" % (testpolicy,testlabel1)}
+
+domain = XmTestDomain(extraConfig=config)
+
+try:
+ console = domain.start()
+except DomainError, e:
+ FAIL(str(e))
+
+# Attach a console to it
+try:
+ console.setHistorySaveCmds(value=True)
+ # Run 'ls'
+ run = console.runCmd("ls")
+except ConsoleError, e:
+ saveLog(console.getHistory())
+ FAIL(str(e))
+
+
+# Explicitly label the 1st resource
+ACMLabelResource(resource1, resourcelabel1)
+block_utils.block_attach(domain, resource1, "sdb1")
+
+try:
+ run1 = console.runCmd("cat /proc/partitions")
+except ConsoleError, e:
+ FAIL(str(e))
+
+#Explicitly label the 2nd resource
+ACMLabelResource(resource2, resourcelabel2)
+#Cannot call block_attach here since we legally may fail the command
+status, output = traceCommand("xm block-attach %s %s %s w" %
+ (domain.getName(), resource2, "sdb2" ))
+
+for i in range(10):
+ if block_utils.get_state(domain, "sdb2") == 4:
+ break
+ time.sleep(1)
+
+try:
+ run2 = console.runCmd("cat /proc/partitions")
+except ConsoleError, e:
+ FAIL(str(e))
+
+# Close the console
+domain.closeConsole()
+
+# Stop the domain (nice shutdown)
+domain.stop()
+
+if not re.search("sdb1",run1["output"]):
+ FAIL("Labeled device 'sdb1' is not actually connected to the domU")
+
+if not re.search("sdb1",run2["output"]):
+ FAIL("Labeled device 'sdb1' has disappeared?!")
+
+if re.search("sdb2",run2["output"]):
+ FAIL("Labeled device 'sdb2' is connected to the domU but should not be")
--- /dev/null
+SUBDIRS =
+
+TESTS = 01_security-acm_basic.test \
+ 02_security-acm_dom_start.test \
+ 03_security-acm_dom_conflict.test \
+ 04_security-acm_dom_res.test \
+ 05_security-acm_dom_res_conf.test \
+ 06_security-acm_dom_block_attach.test
+
+XFAIL_TESTS =
+
+EXTRA_DIST = $(TESTS) $(XFAIL_TESTS) acm_utils.py
+TESTS_ENVIRONMENT=@TENV@
+
+%.test: %.py
+ cp $< $@
+ chmod +x $@
+ @cp -f xm-test-security_policy.xml /etc/xen/acm-security/policies
+
+clean-local: am_config_clean-local
+
+am_config_clean-local:
+ rm -f *test
+ rm -f *log
+ rm -f *~
--- /dev/null
+#!/usr/bin/python
+
+# Copyright (C) International Business Machines Corp., 2006
+# Author: Stefan Berger <stefanb@us.ibm.com>
+
+from XmTestLib import *
+from XmTestLib.acm import *
+
+testpolicy = "xm-test"
+vmconfigfile = "/tmp/xm-test.conf"
+
+if not isACMEnabled():
+ SKIP("Not running this test since ACM not enabled.")
+
+ACMLoadPolicy(testpolicy)
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Auto-generated by ezPolicy -->
+<SecurityPolicyDefinition xmlns="http://www.ibm.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ibm.com ../../security_policy.xsd ">
+ <PolicyHeader>
+ <PolicyName>xm-test</PolicyName>
+ <Date>Fri Sep 29 14:44:38 2006</Date>
+ </PolicyHeader>
+
+ <SimpleTypeEnforcement>
+ <SimpleTypeEnforcementTypes>
+ <Type>SystemManagement</Type>
+ <Type>green</Type>
+ <Type>red</Type>
+ <Type>blue</Type>
+ </SimpleTypeEnforcementTypes>
+ </SimpleTypeEnforcement>
+
+ <ChineseWall priority="PrimaryPolicyComponent">
+ <ChineseWallTypes>
+ <Type>SystemManagement</Type>
+ <Type>green</Type>
+ <Type>red</Type>
+ <Type>blue</Type>
+ </ChineseWallTypes>
+
+ <ConflictSets>
+ <Conflict name="RER">
+ <Type>blue</Type>
+ <Type>red</Type>
+ </Conflict>
+ </ConflictSets>
+ </ChineseWall>
+
+ <SecurityLabelTemplate>
+ <SubjectLabels bootstrap="SystemManagement">
+ <VirtualMachineLabel>
+ <Name>SystemManagement</Name>
+ <SimpleTypeEnforcementTypes>
+ <Type>SystemManagement</Type>
+ <Type>green</Type>
+ <Type>red</Type>
+ <Type>blue</Type>
+ </SimpleTypeEnforcementTypes>
+ <ChineseWallTypes>
+ <Type>SystemManagement</Type>
+ </ChineseWallTypes>
+ </VirtualMachineLabel>
+
+ <VirtualMachineLabel>
+ <Name>green</Name>
+ <SimpleTypeEnforcementTypes>
+ <Type>green</Type>
+ </SimpleTypeEnforcementTypes>
+ <ChineseWallTypes>
+ <Type>green</Type>
+ </ChineseWallTypes>
+ </VirtualMachineLabel>
+
+ <VirtualMachineLabel>
+ <Name>red</Name>
+ <SimpleTypeEnforcementTypes>
+ <Type>red</Type>
+ </SimpleTypeEnforcementTypes>
+ <ChineseWallTypes>
+ <Type>red</Type>
+ </ChineseWallTypes>
+ </VirtualMachineLabel>
+
+ <VirtualMachineLabel>
+ <Name>blue</Name>
+ <SimpleTypeEnforcementTypes>
+ <Type>blue</Type>
+ </SimpleTypeEnforcementTypes>
+ <ChineseWallTypes>
+ <Type>blue</Type>
+ </ChineseWallTypes>
+ </VirtualMachineLabel>
+ </SubjectLabels>
+
+ <ObjectLabels>
+ <ResourceLabel>
+ <Name>SystemManagement</Name>
+ <SimpleTypeEnforcementTypes>
+ <Type>SystemManagement</Type>
+ </SimpleTypeEnforcementTypes>
+ </ResourceLabel>
+
+ <ResourceLabel>
+ <Name>green</Name>
+ <SimpleTypeEnforcementTypes>
+ <Type>green</Type>
+ </SimpleTypeEnforcementTypes>
+ </ResourceLabel>
+
+ <ResourceLabel>
+ <Name>red</Name>
+ <SimpleTypeEnforcementTypes>
+ <Type>red</Type>
+ </SimpleTypeEnforcementTypes>
+ </ResourceLabel>
+
+ <ResourceLabel>
+ <Name>blue</Name>
+ <SimpleTypeEnforcementTypes>
+ <Type>blue</Type>
+ </SimpleTypeEnforcementTypes>
+ </ResourceLabel>
+ </ObjectLabels>
+ </SecurityLabelTemplate>
+</SecurityPolicyDefinition>